package cn.sc.summer.token.util;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.sc.summer.constant.encrypt.EncryptKeyConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

/**
 * 类名：AES加密工具类，根据不同的加密模式进行加密算法
 *
 * @author a-xin
 * @date 2023/7/31 10:12
 */
@Slf4j
public class AESUtil {

    /**
     * 加密方式
     */
    public static final String ALGORITHM = "AES";

    /**
     * 指定填充方式
     */
    private static final String CIPHER_PADDING = "AES/ECB/PKCS5Padding";

    /**
     * 指定填充方式-CBC模式
     */
    private static final String CIPHER_CBC_PADDING = "AES/CBC/PKCS5Padding";

    /**
     * AES加密
     *
     * @param content 待加密内容
     * @param aesKey  密码/秘钥
     * @return AES加密后信息
     */
    public static String encrypt(String content, String aesKey) {
        if (StrUtil.isBlank(content)) {
            return content;
//            throw new RuntimeException("AES decrypt: the content is null!");
        }
        if (StrUtil.isNotBlank(aesKey) && aesKey.length() == 16) {
            try {
                byte[] bytes = aesKey.getBytes(StandardCharsets.UTF_8);
                SecretKeySpec skeySpec = new SecretKeySpec(bytes, ALGORITHM);
                Cipher cipher = Cipher.getInstance(CIPHER_PADDING);
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
                byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
                return Base64Utils.encodeToString(encrypted);
            } catch (Exception e) {
                throw new RuntimeException("AES encrypt exception:" + e.getMessage(), e);
            }
        } else {
            log.info("AES encrypt: the aesKey is null or error!");
            return null;
        }
    }

    /**
     * AES解密
     *
     * @param content 待解密内容
     * @param aesKey  密码/秘钥
     * @return 解密后明文信息
     */
    public static String decrypt(String content, String aesKey) {
        if (CharSequenceUtil.isBlank(content)) {
            return content;
//            throw new RuntimeException("AES decrypt: the content is null!");
        }
        if (StrUtil.isNotBlank(aesKey) && aesKey.length() == 16) {
            try {
                byte[] bytes = aesKey.getBytes(StandardCharsets.UTF_8);
                SecretKeySpec skeySpec = new SecretKeySpec(bytes, ALGORITHM);
                Cipher cipher = Cipher.getInstance(CIPHER_PADDING);
                cipher.init(Cipher.DECRYPT_MODE, skeySpec);
                byte[] decodeBase64 = Base64Utils.decodeFromString(content);
                byte[] decrypted = cipher.doFinal(decodeBase64);
                return new String(decrypted, StandardCharsets.UTF_8);
            } catch (Exception e) {
                throw new RuntimeException("AES decrypt exception:" + e.getMessage(), e);
            }
        } else {
            throw new RuntimeException("AES decrypt: the aesKey is null or error!");
        }
    }

    /**
     * AES_CBC加密
     *
     * @param content 待加密内容
     * @param aesKey  密码/密钥
     * @return AES_CBC加密后信息
     */
    public static String encryptCBC(String content, String aesKey) {
        if (StrUtil.isBlank(content)) {
            return content;
//            throw new RuntimeException("AES CBC encryptCBC: the content is null!");
        }
        //判断秘钥是否为16位
        if (StrUtil.isNotBlank(aesKey) && aesKey.length() == 16) {
            try {
                byte[] bytes = aesKey.getBytes(StandardCharsets.UTF_8);
                SecretKeySpec skeySpec = new SecretKeySpec(bytes, ALGORITHM);
                Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING);
                IvParameterSpec iv = new IvParameterSpec(EncryptKeyConstant.AES_IV_SEED.getBytes(StandardCharsets.UTF_8));
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
                byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
                return Base64Utils.encodeToString(encrypted);
            } catch (Exception e) {
                throw new RuntimeException("AES_CBC encrypt exception:" + e.getMessage(), e);
            }
        } else {
            throw new RuntimeException("AES_CBC encrypt: the aesKey is null or error!");
        }
    }

    /**
     * AES_CBC解密
     *
     * @param content 待解密内容
     * @param aesKey  密码/秘钥
     * @return AES_CBC解密明文信息
     */
    public static String decryptCBC(String content, String aesKey) {
        if (StrUtil.isBlank(content)) {
            return content;
//            throw new RuntimeException("AES CBC encryptCBC: the content is null!");
        }
        if (StrUtil.isNotBlank(aesKey) && aesKey.length() == 16) {
            try {
                byte[] bytes = aesKey.getBytes(StandardCharsets.UTF_8);
                SecretKeySpec skeySpec = new SecretKeySpec(bytes, ALGORITHM);
                IvParameterSpec iv = new IvParameterSpec(EncryptKeyConstant.AES_IV_SEED.getBytes(StandardCharsets.UTF_8));
                Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING);
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
                byte[] decodeBase64 = Base64Utils.decodeFromString(content);
                byte[] decrypted = cipher.doFinal(decodeBase64);
                return new String(decrypted, StandardCharsets.UTF_8);
            } catch (Exception e) {
                throw new RuntimeException("AES_CBC decrypt exception:" + e.getMessage(), e);
            }
        } else {
            throw new RuntimeException("AES_CBC decrypt: the aesKey is null or error!");
        }
    }

}
